#pragma once

#include <iostream>
#include <string>
#include <jsoncpp/json/json.h>
#include <unistd.h>
#include<memory>

//指定协议

namespace protocol_ns
{
    const std::string SEP = "\r\n"; // 分隔符

    // 添加报头（有效载荷已经序列化）
    // 报文：len\r\n{       }\r\n
    std::string Encode(const std::string &json_str)
    {
        int json_str_len = json_str.size(); // 计算长度

        std::string proto_str = std::to_string(json_str_len); // 报文

        proto_str += SEP;      // 分隔符
        proto_str += json_str; // 有效载荷
        proto_str += SEP;

        return proto_str;
    }

    // len\r\n{
    // len\r\n{       }
    // len\r\n{       }\r\n
    // len\r\n{       }\r\nlen\r\n{
    // len\r\n{       }\r\nlen\r\n{       }\r
    // len\r\n{       }\r\nlen\r\n{       }\r\n
    // len\r\n{       }\r\nlen\r\n{       }\r\nlen\r
    // len\r\n{       }\r\nlen\r\n{       }\r\nlen\r\n{       }\r\n

    //  分离出有效载荷（但收到的报文不一定是完整的，判断收到的报文中有一个完整的报文，就可以进行分离）
    std::string Decode(std::string &inbuffer)
    {
        auto pos = inbuffer.find(SEP);

        // 报文不完整
        if (pos == std::string::npos)
            return std::string();

        std::string len_str = inbuffer.substr(0, pos);
        if (len_str.empty())
            return std::string();

        int packlen = std::stoi(len_str); // 有效载荷的长度

        int total = packlen + 2 * SEP.size() + len_str.size(); // 完整报文的长度

        if (inbuffer.size() < total)
            return std::string(); // 不是完整报文

        std::string package = inbuffer.substr(pos + SEP.size(), packlen); // 有效载荷

        inbuffer.erase(0, total); // 在报文中去掉完整的一段，避免重复处理
        return package;
    }

    // 请求，客户端向服务器发送请求
    class Request
    {
    public:
        Request()
        {
        }
        Request(int x, int y, char oper)
            : _x(x), _y(y), _oper(oper)
        {
        }

        // 序列化，out 是输出型参数
        // 客户端发送请求时，将请求序列化
        bool Serialize(std::string *out)
        {
            Json::Value root;
            root["x"] = _x;
            root["y"] = _y;
            root["oper"] = _oper;

            Json::FastWriter writer;
            *out = writer.write(root); // 将 root 序列化为字符串

            return true;
        }

        // 反序列化
        // 服务器收到请求，将请求反序列化
        bool Deserialize(const std::string &in)
        {
            Json::Value root;
            Json::Reader reader; // 从字符串中读取 Json 数据

            bool res = reader.parse(in, root); // 解析

            // 解析失败
            if (!res)
                return false;

            // 解析成功
            _x = root["x"].asInt();
            _y = root["y"].asInt();
            _oper = root["oper"].asInt();

            return true;
        }

    public:
        int _x;     // 左操作数
        int _y;     // 右操作数
        char _oper; // 操作符
    };

    // 应答
    // 服务器处理完请求，向客户端发送应答
    class Response
    {
    public:
        Response()
        {
        }
        Response(int result, int code)
            : _result(result), _code(code)
        {
        }
        // 序列化，out 是输出型参数
        // 将应答序列化，发送给客户端
        bool Serialize(std::string *out)
        {
            Json::Value root;
            root["result"] = _result;
            root["code"] = _code;

            Json::FastWriter writer;
            *out = writer.write(root); // 将 root 序列化为字符串

            return true;
        }

        // 反序列化
        // 客户端收到应答，将应答反序列化
        bool Deserialize(const std::string &in)
        {
            Json::Value root;
            Json::Reader reader; // 从字符串中读取 Json 数据

            bool res = reader.parse(in, root); // 解析

            // 解析失败
            if (!res)
                return false;

            // 解析成功
            _result = root["result"].asInt();
            _code = root["code"].asInt();

            return true;
        }

    public:
        int _result; // 运算结果
        int _code;   // 结果是否可信，0：可信，1：除0，2：非法操作
    };

    // 工厂，创造数据
    // 模拟客户端
    class Factory
    {
    public:
        Factory()
        {
            srand(time(nullptr) ^ getpid());
            opers = "+/*/%^&|";
        }
        std::shared_ptr<Request> BuildRequest()
        {
            int x = rand() % 10 + 1;
            usleep(x * 10);
            int y = rand() % 5; 
            usleep(y * x * 5);
            char oper = opers[rand() % opers.size()];
            std::shared_ptr<Request> req = std::make_shared<Request>(x, y, oper);
            return req;
        }
        std::shared_ptr<Response> BuildResponse()
        {
            return std::make_shared<Response>();
        }
        ~Factory()
        {
        }

    private:
        std::string opers;
    };
}